/**
 * @filename:PickMaterialServiceImpl Dec 15, 2023
 * @project Wonder Vue Admin Api  1.1.0
 * Copyright(c) 2022 Wonder Co. Ltd. 
 * All right reserved. 
 */
package com.wonder.app.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.vtuzx.core.VtuzxException;
import com.vtuzx.core.bean.dto.VtuzxMap;
import com.vtuzx.core.utils.VtuzxUtil;
import com.wonder.app.domain.*;
import com.wonder.app.mapper.*;
import com.wonder.app.request.ProppbomlistRequest;
import com.wonder.app.service.*;
import com.wonder.app.request.PickMaterialRequest;
import com.wonder.bean.kingdee.xqc.BillMaterial;
import com.wonder.common.exception.CustomException;
import com.wonder.common.utils.DateUtils;
import com.wonder.common.utils.MapUtils;
import com.wonder.common.utils.StringUtils;
import com.wonder.common.utils.MessageUtils;
import com.wonder.common.common.AjaxResult;

import java.util.*;
import java.util.stream.Collectors;

import com.wonder.constant.BillEvent;
import com.wonder.constant.BillType;
import com.wonder.constant.IXqcConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

/**   
 * @Description:TODO(生产领料单服务实现)
 *
 * @version: 1.1.0
 * @author: Wonder
 * 
 */
@Service
public class PickMaterialServiceImpl  extends ServiceImpl<PickMaterialDao, PickMaterial> implements PickMaterialService  {
	/**
	 * Logger
	 */
	private static final Logger _logger = LoggerFactory.getLogger(PickMaterialServiceImpl.class);


	@Autowired
	private PickMaterialDetailDao pickMaterialDetailDao;

	@Autowired
	private PickMaterialDetailService pickMaterialDetailService;

	@Autowired
	private PickMaterialDao pickMaterialDao;

	@Autowired
	private ProppbomlistDao proppbomlistDao;

	@Autowired
	private PickMaterialService pickMaterialService;


	@Autowired
	private InventoryService inventoryService;

	@Autowired
	private ProppbomDao proppbomDao;

	@Autowired
	private ProppbomService proppbomService;

	@Autowired
	private KingdeeOrderService kingdeeOrderService;

	@Autowired
	private ProorderDao proorderDao;

	@Autowired
	private ProppbomlistService proppbomlistService;

	@Autowired
	private MaterialDao materialDao;
    /**
     * 验证生产领料单信息
     * 
     * @param pickMaterial
     * @param type
     * @return String
     */
    @Override
    public String validate(PickMaterial pickMaterial,String type){
    
    
       return "";
    }
    
    
    /**
	 * Description:生产领料单分页返回
	 * @param request //检索条件
	 * @param page //分页参数
	 * @return IPage<PickMaterial>   //分页记录
	 */
	@Override 
	public IPage<PickMaterial> selectList(PickMaterialRequest request, Page<PickMaterial> page){
	    LambdaQueryWrapper<PickMaterial> lambdaQueryWrapper = new LambdaQueryWrapper<>();
	    
	    if (null != request.getId()) {
	       lambdaQueryWrapper.eq(PickMaterial::getId, request.getId());
	      }               
	    if (null != request.getBillNo()){
	    	lambdaQueryWrapper.like(PickMaterial::getBillNo,request.getBillNo());
		}
		if (null != request.getTaskBillNo()){
			lambdaQueryWrapper.like(PickMaterial::getTaskBillNo,request.getTaskBillNo());
		}

		if (request.getCreateTime() != null){
			Date[] createTime=request.getCreateTime();
			if(createTime.length>0)
				lambdaQueryWrapper.ge(PickMaterial::getCreateTime, createTime[0]);
			if(createTime.length==2)
				lambdaQueryWrapper.le(PickMaterial::getCreateTime, DateUtils.dateToStr(createTime[1],"yyyy-MM-dd")+ " 23:59:59");

		}
        
		lambdaQueryWrapper.orderByDesc(PickMaterial::getId);	
		Page<PickMaterial> selectPage = this.baseMapper.selectPage(page, lambdaQueryWrapper);
		return selectPage;
    }

	@Override
	public VtuzxMap getDetail(String billNo) {
		VtuzxMap data = new VtuzxMap();
		PickMaterial pickMaterial = pickMaterialDao.selectOne(new QueryWrapper<PickMaterial>().eq("billNo",billNo));
		List<PickMaterialDetail> pickMaterialDetailList = pickMaterialDetailDao.selectList(new QueryWrapper<PickMaterialDetail>().eq("billNo", billNo));
		data.append("header",pickMaterial)
				.append("dataList",pickMaterialDetailList);
		return data;
	}

	@Override
	public boolean unAuditPickMaterial(Long userId,String userName,String billNo) throws Exception{
		PickMaterial pickMaterial = pickMaterialDao
				.selectOne(new LambdaQueryWrapper<PickMaterial>().eq(PickMaterial::getBillNo,billNo));
		pickMaterial.setUpdateTime(new DateTime());
		pickMaterial.setUpdateUserName(userName);
		pickMaterial.setStatus("unAudit");

		//反审需要把扣减掉的库存增加
		List<PickMaterialDetail> detailList = pickMaterialDetailDao.selectList(new QueryWrapper<PickMaterialDetail>()
				.eq("billNo", billNo));

		List<BillMaterial> dataList = new ArrayList<>();//需要增加的库存
		for (PickMaterialDetail data : detailList) {
				BillMaterial material = new BillMaterial();
				material.setMaterialNo(data.getMaterialNo());
				material.setMaterialName(data.getMaterialName());
				material.setMaterialModel(data.getSpecification());
				material.setCount(data.getCount());
				material.setStockNo(data.getStockNo());
				material.setBatchNo(data.getFlot());
				material.setUnit(data.getUnit());
				material.setProduceDate(data.getProduceDate());
				material.setExpiryDate(data.getExpiryDate());
				material.setProduce(data.getIsProduce());
				material.setFlot(data.getIsFlot());
				dataList.add(material);
		}
		try {
			Map<String, Object> stringObjectMap = inventoryService.addInventory(userId, userName, BillEvent.Unaudit, BillType.SCLL, billNo, dataList);
			if (!(Boolean) stringObjectMap.get("status")){
				return false;
			}
		} catch (Exception e){
			_logger.info(e.getMessage());
		}

		boolean isSuccess = pickMaterialService.updateById(pickMaterial);

		return isSuccess;
	}

	@Override
	public boolean auditPickMaterial(Long userId,String userName, String billNo) throws Exception {
		PickMaterial pickMaterial = pickMaterialDao
				.selectOne(new LambdaQueryWrapper<PickMaterial>().eq(PickMaterial::getBillNo,billNo));
		pickMaterial.setUpdateTime(new DateTime());
		pickMaterial.setUpdateUserName(userName);
		pickMaterial.setStatus("audit");
		pickMaterial.setAuditTime(new DateTime());
		pickMaterial.setAuditUserName(userName);

		//审核订单需要扣减库存
		List<PickMaterialDetail> detailList = pickMaterialDetailDao.selectList(new QueryWrapper<PickMaterialDetail>()
				.eq("billNo", billNo));

		List<BillMaterial> dataList = new ArrayList<>();//需要扣减的库存
		for (PickMaterialDetail data : detailList) {
			BillMaterial material = new BillMaterial();
			material.setMaterialNo(data.getMaterialNo());
			material.setMaterialName(data.getMaterialName());
			material.setMaterialModel(data.getSpecification());
			material.setCount(data.getCount());
			material.setStockNo(data.getStockNo());
			material.setBatchNo(data.getFlot());
			material.setUnit(data.getUnit());
			material.setProduceDate(data.getProduceDate());
			material.setExpiryDate(data.getExpiryDate());
			material.setProduce(data.getIsProduce());
			material.setFlot(data.getIsFlot());
			material.setWorkShop(data.getWorkShop());
			dataList.add(material);
		}
		boolean isSuccess = pickMaterialService.updateById(pickMaterial);
		try {
			Map<String, Object> stringObjectMap = inventoryService.reduceInventory(userId, userName, BillEvent.Audit, BillType.SCLL, billNo, dataList);
			if (!(Boolean) stringObjectMap.get("status")){
				return false;
			}

		} catch (Exception e){
			_logger.info(e.getMessage());
			throw new VtuzxException(e.getMessage());
		}
		//穿金蝶其他出库
//		try {
//			//传金蝶其他入库单
//			Map<String, Object> map = MapUtils.objectToMap(pickMaterial);
//
//			List<Map<String, Object>> objectList = detailList
//					.stream().map(obj -> BeanUtil.beanToMap(obj)).collect(Collectors.toList());
//			kingdeeOrderService.syncOtherOut(userId,userName,map,objectList);
//		} catch (Exception e){
//			_logger.info(e.getMessage());
//		}



		return isSuccess;
	}

	@Override
	public VtuzxMap getPickPpbom(String taskBillNo) {
		VtuzxMap data = new VtuzxMap();
		List<Proppbomlist> bomList = proppbomlistDao.selectList(new QueryWrapper<Proppbomlist>().eq("taskBillNo", taskBillNo));


		return data.append("dataList",bomList);
	}

	@Override
	public VtuzxMap changePickMaterial(Long user_id, String userName,Map<String,Object> header, List<Map<String, Object>> dataList) {

		Long id = Long.parseLong(header.get("id").toString());
		String taskBillNo = header.get("taskBillNo").toString();

		//1.删除之前的领料详情信息
		int deleteCount = pickMaterialDetailDao.delete(new QueryWrapper<PickMaterialDetail>().eq("entryId", id));
		//添加新的领料信息
		List<PickMaterialDetail> detailList = new ArrayList<>();
		for (Map<String, Object> map : dataList) {
			PickMaterialDetail detail = new PickMaterialDetail();
			detail.setMaterialNo(map.get("materialNo").toString());
			detail.setMaterialName(map.get("materialName").toString());
			detail.setSpecification(map.get("specification").toString());
			detail.setCount(Double.parseDouble(map.get("stdQty").toString()));
			detail.setUnit(map.get("unit").toString());
			detail.setTaskBillNo(taskBillNo);
			detail.setEntryId(id);
			detail.setPBomNo(map.get("billNo").toString());
			detail.setIsFlot((Boolean) map.get("isFlot"));
			detail.setIsProduce((Boolean) map.get("isProduce"));
			detail.setCreateTime(new DateTime());
			detail.setCreateUserId(user_id);
			detail.setCreateUserName(userName);
			detail.setUpdateTime(new DateTime());
			detail.setUpdateUserName(userName);
			detailList.add(detail);
		}
		boolean isSuccess = pickMaterialDetailService.saveBatch(detailList);
		return new VtuzxMap("res",isSuccess).append("dataList",detailList);
	}

	@Override
	public boolean savePickDetail(String userName,Map<String,Object> header, List<Map<String,Object>> dataList) {
		List<PickMaterialDetail> detailList = new ArrayList<>();
		double sumCount = 0;
		for (Map<String,Object> map : dataList) {
			PickMaterialDetail detail = new PickMaterialDetail();
			detail.setId(VtuzxUtil.getLong(map,"id"));
			detail.setBillNo(VtuzxUtil.getString(map,"billNo"));
			detail.setMaterialNo(VtuzxUtil.getString(map,"materialNo"));
			detail.setMaterialName(VtuzxUtil.getString(map,"materialName"));
			detail.setSpecification(VtuzxUtil.getString(map,"specification"));
			detail.setFlot(VtuzxUtil.getString(map,"flot"));

			detail.setProduceDate(VtuzxUtil.parseDate(VtuzxUtil.getString(map,"produceDate")));
			detail.setExpiryDate(VtuzxUtil.parseDate(VtuzxUtil.getString(map,"expiryDate")));
			detail.setUnit(VtuzxUtil.getString(map,"unit"));
			detail.setStockNo(VtuzxUtil.getString(map,"stockNo"));
			detail.setWorkShop(VtuzxUtil.getString(map,"workShop"));
			detail.setTaskBillNo(VtuzxUtil.getString(map,"taskBillNo"));
			detail.setPBomNo(VtuzxUtil.getString(map,"pbomNo"));
			detail.setCount(VtuzxUtil.getDouble(map,"count"));
			detail.setIsProduce(VtuzxUtil.getBoolean(map,"isProduce"));
			detail.setIsFlot(VtuzxUtil.getBoolean(map,"isFlot"));
			detail.setUpdateUserName(userName);
			detail.setUpdateTime(new DateTime());
			detailList.add(detail);
			sumCount += VtuzxUtil.getDouble(map,"count");
		}
		//修改外层的数量
		Long id = Long.parseLong(header.get("id").toString());
		PickMaterial pickMaterial = pickMaterialDao.selectById(id);
		pickMaterial.setCount(sumCount);
		pickMaterial.setStatus("save");
		boolean pickRes = pickMaterialService.updateById(pickMaterial);
		boolean res = pickMaterialDetailService.saveOrUpdateBatch(detailList);
		return res && pickRes;
	}

	@Override
	public Boolean savePickMaterialPad(JSONObject map) {
		String billNoS = map.getStr("taskBillNo");
		JSONArray data = map.getJSONArray("data");
		String userName = map.getStr("userName");
		//获取到所有的订单号
		String[] split = billNoS.split(",");
		Map<String,Object> materialMap = new HashMap<>();//key:物料编码+车间 val:所需重量
		Map<String,Object> taskMap = new HashMap<>();//key:订单号 val:订单所需的物料信息
		Map<String,Object> orderMap = new HashMap<>();//key: 订单号 val:车间信息
		//查询生成订单获取车间信息
		List<Proorder> proorderList = proorderDao.selectList(new LambdaQueryWrapper<Proorder>().in(Proorder::getBillNo, split));
		List<Proppbom> headList = proppbomDao.selectList(new LambdaQueryWrapper<Proppbom>().in(Proppbom::getTaskBillNo, split));
		List<Proppbomlist> detailList = proppbomlistDao.selectList(new LambdaQueryWrapper<Proppbomlist>().in(Proppbomlist::getTaskBillNo, split));
		for (Proorder proorder : proorderList){
			String billNo = proorder.getBillNo();
			String workShop = proorder.getWorkShop();
			orderMap.put(billNo,workShop);
		}
		for (Proppbom proppbom : headList){
			String billNo = proppbom.getTaskBillNo();
			double count = proppbom.getFqty();
			for (Proppbomlist proppbomlist : detailList){
				String detailBillNo = proppbomlist.getTaskBillNo();
				if (billNo.equals(detailBillNo)){
					Double numerator = proppbomlist.getNumerator();//分子
					Double denominator = proppbomlist.getDenominator();//分母
					String materialNo = proppbomlist.getMaterialNo();
					double needQty = count * numerator / denominator;//当前物料所需要的数量
					String workShop = VtuzxUtil.getString(orderMap,billNo);//车间信息

					//从taskmap获取数据判断当前订单号有没有值,有的话添加,没有的话做新增
					List<VtuzxMap> materialList = (List<VtuzxMap>) taskMap.get(billNo);
					if(null != materialList){//如果有值
						VtuzxMap vtuzxMap = new VtuzxMap();
						vtuzxMap.append("materialNo",materialNo)
								.append("workShop",workShop)
								.append("count",needQty);
						materialList.add(vtuzxMap);
						taskMap.put(billNo,materialList);
					} else {//没有值的话
						List<VtuzxMap> mapList = new ArrayList<>();
						VtuzxMap newMap = new VtuzxMap();
						newMap.append("materialNo",materialNo)
								.append("workShop",workShop)
								.append("count",needQty);
						mapList.add(newMap);
						taskMap.put(billNo,mapList);
					}
					//从materialMap中获取物料重量进行判断,有值的话做增加,没有就新增一条
					Double materialCount = (Double) materialMap.get(materialNo + "," + workShop);
					if ( null != materialCount){//有值的话
						materialMap.put(materialNo + "," + workShop, materialCount + needQty);
					} else {//没有值的话
						materialMap.put(materialNo + "," + workShop,needQty);
					}
				}
			}
		}
		//判断现在的数量和传过来的数量是否相等,
		//如果相等的话就按照计算的数量做领料,
		//如果不相等的话把多出来的数量平均分到每个订单上
		Map<String,Object> workMap = new HashMap<>();//key:物料  val:车间
		Map<String,Object> needMaterial = new HashMap<>();//key:物料+车间 val :物料所需要增加的重量
		for (int i = 0;i < data.size();i++){
			JSONObject jsonObject = data.getJSONObject(i);
			String materialNo = jsonObject.getStr("materialNo");
			Double count = jsonObject.getDouble("count");//工业平板传过来的实际领料重量
			String workShop = jsonObject.getStr("workShop");//车间
			double materialCount = VtuzxUtil.getDouble(materialMap,materialNo + "," + workShop);//根据订单计算的所需重量
			if (count == materialCount){
				needMaterial.put(materialNo + "," + workShop,0);
			} else if (count > materialCount){
				needMaterial.put(materialNo + "," + workShop,(count - materialCount)/split.length);
			} else if (count < materialCount){
				needMaterial.put(materialNo + "," + workShop,(count - materialCount)/split.length);
			}
		}
		//循环taskMap计算出最终所需要的领料重量
		for (Map.Entry entry : taskMap.entrySet()){
			List<VtuzxMap> materialList = (List<VtuzxMap>) entry.getValue();
			for (VtuzxMap dataMap : materialList){
				String materialNo = VtuzxUtil.getString(dataMap,"materialNo");
				String workShop = VtuzxUtil.getString(dataMap,"workShop");
				double count = VtuzxUtil.getDouble(dataMap,"count");
				double needCount = VtuzxUtil.getDouble(needMaterial,materialNo + "," + workShop);
				if (needCount != 0){
					dataMap.put("count",count + needCount);
				}
			}
		}
		//生成领料单并审核
		Boolean res = savePickMaterial(userName, taskMap);
		return res;
	}

	/**
	 * 生成领料单
	 * @param data
	 */
	private Boolean savePickMaterial(String userName,Map<String,Object> data){
		List<PickMaterial> pickMaterialList = new ArrayList<>();//领料外层表
		List<PickMaterialDetail> detailList = new ArrayList<>();//领料详情表
		//循环添加领料信息
		for (Map.Entry entry : data.entrySet()){
			String taskBillNo = (String) entry.getKey();
			List<VtuzxMap> materialList = (List<VtuzxMap>) entry.getValue();

			String billNo = IXqcConst.createBillNo(BillType.SCLL);
			PickMaterial pickMaterial = new PickMaterial();
			pickMaterial.setBillNo(billNo);
			pickMaterial.setStatus("save");
			pickMaterial.setPicker(userName);
			pickMaterial.setStocker(userName);
			pickMaterial.setTaskBillNo(taskBillNo);

			Double sumCount = 0.d;//外层总的领料数量
			for (VtuzxMap dataMap : materialList){
				String materialNo = VtuzxUtil.getString(dataMap,"materialNo");
				double count = VtuzxUtil.getDouble(dataMap,"count");
				String workShop = VtuzxUtil.getString(dataMap,"workShop");
				sumCount += count;
				//先从物料表查询规格名称单位
				Material material = materialDao.selectOne(new QueryWrapper<Material>().eq("FNumber", materialNo));
				String specification = material.getFSPECIFICATION();
				String materialName = material.getFName();
				String unit = material.getUnit();
				Boolean fIsFlot = material.getFIsFlot();
				Boolean fIsProduce = material.getFIsProduce();
				PickMaterialDetail detail = new PickMaterialDetail();
				detail.setBillNo(billNo);
				detail.setMaterialName(materialName);
				detail.setSpecification(specification);
				detail.setMaterialNo(materialNo);
				detail.setUnit(unit);
				detail.setTaskBillNo(taskBillNo);
				//仓库全是岗上仓库
				detail.setStockNo("00");
				detail.setWorkShop(workShop);//添加车间信息
				detail.setCount(count);
				detail.setIsProduce(fIsProduce);
				detail.setIsFlot(fIsFlot);
				detailList.add(detail);
			}
			pickMaterial.setCount(sumCount);
			pickMaterialList.add(pickMaterial);
		}
		//数据库添加领料信息
		boolean headRes = pickMaterialService.saveBatch(pickMaterialList);
		boolean detailRes = pickMaterialDetailService.saveBatch(detailList);
		//审核领料单
		for (PickMaterial pickMaterial : pickMaterialList){
			String billNo = pickMaterial.getBillNo();
			Long createUserId = pickMaterial.getCreateUserId();
			String createUserName = pickMaterial.getCreateUserName();
			try {
				auditPickMaterial(createUserId,createUserName,billNo);
			} catch (Exception e){
				throw new CustomException(e.getMessage());
			}
		}
		return headRes && detailRes;
	}
}